#include "SQLDropDatabaseStatement.h"

#include "../SQLName.h"
#include "../../../DbType.h"
#include "SQLDDLStatement.h"
#include "../../visitor/SQLASTVisitor.h"
#include "../SQLObject.h"
#include "../SQLExpr.h"
#include "../../../utils/instanceof.h"
#include "../../SQLUtils.h"

SQLDropDatabaseStatement::SQLDropDatabaseStatement()
{
}

SQLDropDatabaseStatement::SQLDropDatabaseStatement(DbType_ptr  dbType)
    : SQLStatementImpl(dbType)
{
}

void SQLDropDatabaseStatement::accept0(SQLASTVisitor_ptr visitor)
{
  if (visitor->visit(SharedObject(SQLDropDatabaseStatement)))
  {
    acceptChild(visitor, database);
  }
  visitor->endVisit(SharedObject(SQLDropDatabaseStatement));
}

SQLName_ptr SQLDropDatabaseStatement::getName()
{
  return std::dynamic_pointer_cast<SQLName>(database);
}

string_ptr  SQLDropDatabaseStatement::getDatabaseName()
{
  if (database == NULL)
  {
    return NULL;
  }

  if (instanceof <SQLExpr, SQLName>(database))
  {
    return ((std::dynamic_pointer_cast<SQLName>(database))->getSimpleName());
  }

  return NULL;
}

SQLExpr_ptr SQLDropDatabaseStatement::getDatabase()
{
  return database;
}

void SQLDropDatabaseStatement::setDatabase(SQLExpr_ptr database)
{
  if (database != NULL)
  {
    database->setParent(SharedObject(SQLDropDatabaseStatement));
  }
  this->database = database;
}

void SQLDropDatabaseStatement::setDatabase(string_ptr  database)
{
  SQLExpr_ptr expr = SQLUtils::toSQLExpr(database);

  if (instanceof <SQLExpr, SQLIdentifierExpr>(expr) && instanceof <SQLExpr, SQLPropertyExpr>(this->database))
  {
    (std::dynamic_pointer_cast<SQLPropertyExpr>(this->database))->setName((database));
    return;
  }

  expr->setParent(SharedObject(SQLDropDatabaseStatement));
  this->database = expr;
}

string_ptr  SQLDropDatabaseStatement::getServer()
{
  if (instanceof <SQLExpr, SQLPropertyExpr>(database))
  {
    SQLExpr_ptr owner = (std::dynamic_pointer_cast<SQLPropertyExpr>(database))->getOwner();
    if (instanceof <SQLExpr, SQLIdentifierExpr>(owner))
    {
      return ((std::dynamic_pointer_cast<SQLIdentifierExpr>(owner))->getName());
    }

    if (instanceof <SQLExpr, SQLPropertyExpr>(owner))
    {
      return ((std::dynamic_pointer_cast<SQLPropertyExpr>(owner))->getName());
    }
  }

  return NULL;
}

BOOL_ptr SQLDropDatabaseStatement::setServer(string_ptr  server)
{
  if (database == NULL)
  {
    return BOOL::FALSE;
  }

  if (instanceof <SQLExpr, SQLIdentifierExpr>(database))
  {
    SQLPropertyExpr_ptr propertyExpr = SQLPropertyExpr_ptr(new SQLPropertyExpr(SQLIdentifierExpr_ptr(new SQLIdentifierExpr((server))), (std::dynamic_pointer_cast<SQLIdentifierExpr>(database))->getName()));
    propertyExpr->setParent(SharedObject(SQLDropDatabaseStatement));
    database = propertyExpr;
    return BOOL::TRUE;
  }

  if (instanceof <SQLExpr, SQLPropertyExpr>(database))
  {
    SQLPropertyExpr_ptr propertyExpr = std::dynamic_pointer_cast<SQLPropertyExpr>(database);
    SQLExpr_ptr owner = propertyExpr->getOwner();
    if (instanceof <SQLExpr, SQLIdentifierExpr>(owner))
    {
      propertyExpr->setOwner(SQLIdentifierExpr_ptr(new SQLIdentifierExpr((server))));
      return BOOL::TRUE;
    }
    else if (instanceof <SQLExpr, SQLPropertyExpr>(owner))
    {
      (std::dynamic_pointer_cast<SQLPropertyExpr>(owner))->setName((server));
      return BOOL::TRUE;
    }
  }

  return BOOL::FALSE;
}

BOOL_ptr SQLDropDatabaseStatement::isIfExists()
{
  return ifExists;
}

void SQLDropDatabaseStatement::setIfExists(BOOL_ptr ifExists)
{
  this->ifExists = ifExists;
}

SQLObject_list_ptr SQLDropDatabaseStatement::getChildren()
{
  SQLObject_list_ptr children = std::make_shared<std::list<SQLObject_ptr>>();
  if (database != NULL)
  {
    children->push_back(database);
  }
  return children;
}

BOOL_ptr SQLDropDatabaseStatement::replace(SQLExpr_ptr expr, SQLExpr_ptr target)
{
  if (database == expr)
  {
    setDatabase(target);
    return BOOL::TRUE;
  }

  return BOOL::FALSE;
}

BOOL_ptr SQLDropDatabaseStatement::getRestrict()
{
  return restrict;
}

BOOL_ptr SQLDropDatabaseStatement::isRestrict()
{
  // if (restrict == NULL)
  // {
  //   return !cascade;
  // }
  return restrict;
}

void SQLDropDatabaseStatement::setRestrict(BOOL_ptr restrict)
{
  this->restrict = restrict;
}

BOOL_ptr SQLDropDatabaseStatement::isCascade()
{
  return cascade;
}

void SQLDropDatabaseStatement::setCascade(BOOL_ptr cascade)
{
  this->cascade = cascade;
}

BOOL_ptr SQLDropDatabaseStatement::isPhysical()
{
  return physical;
}

void SQLDropDatabaseStatement::setPhysical(BOOL_ptr physical)
{
  this->physical = physical;
}

SQLDDLStatement::DDLObjectType SQLDropDatabaseStatement::getDDLObjectType()
{
  return SQLDDLStatement::DDLObjectType::DATABASE;
}
